<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Cache\RateLimiter;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpKernel\Exception\HttpException;

class SDKToken
{
    /**
     *
     * @param $request
     * @param Closure $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        // 本地跳过验签
        if (app()->environment('local')) {
            return $next($request);
        }

        try {
            $params = $request->except(['s', 'signature']);
            $signatureBak = $request->get('signature', '');

            // 计算签名
            $formatBizQueryParaMap = static function ($paramsMap) use (&$formatBizQueryParaMap) {
                $buff = [];
                ksort($paramsMap);
                foreach ($paramsMap as $k => $v) {
                    if (is_array($v)) {
                        $buff = array_merge($buff, $formatBizQueryParaMap($v));
                    } else {
                        $buff[] = $v;
                    }
                }

                return $buff;
            };
            $paramsHttpBuildQueryAddSecret = implode('&', $formatBizQueryParaMap($params)) . config('auth.sdk_secret');
            $signature = strtolower(md5($paramsHttpBuildQueryAddSecret));

            // 验证时间
            $timestamp = (int) $request->get('timestamp', 0);
            if ($timestamp === 0 || Carbon::now()->gt(Carbon::createFromTimestamp($timestamp)->addMinutes(1))) {
                abort(401, '请求数据已过时');
            }

//            // 验证随机字符串
//            $rateLimiter = app()->make(RateLimiter::class);
//            $nonce = $request->get('nonce', '');
//            empty($nonce) && abort(401, '缺失 nonce');
//            $rateLimiterKey = 'sdk_nonce_' . $request->get('nonce');
//            if ($rateLimiter->tooManyAttempts($rateLimiterKey, 1)) {
//                abort(401, '非法请求数据');
//            }
//            $rateLimiter->hit($rateLimiterKey, 1 * 60); // 一分钟以内只允许出现一次

            if ($signatureBak !== $signature) {
                $signatureErrorLog = [
                    '[签名错误]',
                    'urldecode(http_build_query($params)) . config(\'auth.sdk_secret\')' . $paramsHttpBuildQueryAddSecret,
                    'signature: ' . $signature,
                    '提交的 signature: ' . $signatureBak,
                ];
                Log::warning(implode(' || ', $signatureErrorLog));

                abort(401, '接口签名错误');
            }
        } catch (\Exception $e) {
            abort($e instanceof HttpException ? $e->getStatusCode() : $e->getCode(), '接口签名验证发生错误: ' . $e->getMessage());
        }

        return $next($request);
    }
}
